跟上一次参加相比,进步了不少。得到了12分,虽然第二题的解法效率是个问题,但也算成功通过了。看自己在所有参赛者中的排名,是 1019 / 5164。也算前20%了吧…继续加油

题目1015

但最后一题(题目1015,计算小于某个非负数的有重复位的非负整数个数)彻底没有做出来。即使看别人的解答,也是看了近半天后才弄明白的。关键点:

  1. 把计算 带有重复位的非负整数个数 转换为 计算不带有重复位的非负整数个数。事实上,计算带有重复位的,那么会有重复1位、2位、重复1次和多次等多种情况发生。但计算不带重复位的就变成了全排列问题,简洁了很多。
  2. 把计算非重复位的整数个数问题拆分成 位长度相同 和 位长度小于 两个子问题。后者要简单很多,很容易计算出。前者就需要利用循环来仔细设计,但用心去看,确实是能找到规律的。
  3. 仔细确定循环的边界。自己在确定循环边界上始终存在问题,经常性地搞错;我想是因为没有把问题和解法彻底想清楚。必须在彻底想清楚之后再去写代码,那么就会有一个清晰的边界选择。(边界总是取决于思路)
  4. 写工具函数时利用模拟值、明确描述其作用等方式清晰化。这个题的排列个数计算方法自己也犯了一些错误,就是对其第一个参数s是重排列的首字可选择数,还是全排列的首字最大数,没有思考清楚。比如计算4x,这个时候应该是循环首位1~4调用A(9,1)相加;而不是传入A(4,9)计算。想清楚这个工具函数的作用,才能将其写清楚。

题目1014

题目1014计算最小载重量的题目,自己的思路还是正确的。所以虽然多花了一些时间,还是将其做了出来。复盘去看,自己一开始就应该将着重点考虑为如何设计步进大小,而不是选择起始点。起始点可以简单地选择为最大元素或者平均值上届,都没有问题;但如何步进,其实才是真正的问题。
在选择右边界上,也没有必要非常谨慎。只要算法的步进很快,边界大个一倍,都不算什么很大的问题。所以仍然还是,这个问题的关键点是如何设计步进,而不是两个端点。
如果一开始就想通这一点,那么会更快地做出这道题目。

题目1013

题目1013自己的解法效率上是很有问题的,时间复杂度为O(n平方),侥幸通过了测试。而看社区的解答就太漂亮了。
对每个元素求其模60的值r,然后在一个集合s上保存r的值为1或增加1;同时,对该元素求其模60之后的补,然后去s上查找这个补的计数,如果非空,则将其计入返回值中。非常漂亮的算法。
自己在解题时,想到了通过查找元素的补去计数。但简单思考后没有找到思路就没有继续,侥幸也提交通过了。如果是在面试中,一定会需要尝试用更高效的方法去计算的。是否能想到上述解法呢?
即使让我现在去思考,感觉还是会在一对互补值是否会被重复计数上有点绕。其实前述思路相当于顺序遍历数组,对每个元素查找它与之前的元素是否匹配,如果匹配,则将匹配的值计入结果中。想通这点,才算真正想清楚。
事实上,很多问题用这种变换遍历顺序的思路去思考后,都能发现更简洁的解法。

题目1012

题目1012自己的解法应该效率是没有问题的,但显繁琐。社区中先找到大于当前数n的最小(二进制全1)的数x,然后通过n与输出结果相加刚好为x的关系直接用x-n得到结果的思路显然更加简洁清晰。
自己当时没有往这个思路上想,大概觉得去求x比较麻烦,就没有继续。事实上,求x还蛮简单的。如果快速想到求x的方法,也许自己也可以想到上述解法。

后记

基本上,这个contest花了自己一天的时间。看看那些前排的大牛十几分钟就搞定了所有题目…差距真是巨大。但我的进步还是比较快的,相信下次会更棒,与头部玩家的距离会越来越小。